#!/usr/bin/env python3
import asyncio
import time
from connection import Connection
from logger import Logger
from config import Config
from device import DeviceInfo, get_device_info
import json


class ConnectionManager:
    def __init__(self, client_id: str):
        self.connections = {}
        self.config = Config()
        self.logger = Logger(client_id, self.config.get_log_dir())
        self.client_id = client_id
        self.lock = asyncio.Lock()
        self.logger.register_connection(client_id, 'localhost', 0)
        
        # 设置老化时间阈值（2小时，单位：秒）
        self.AGING_THRESHOLD = 2 * 60 * 60
        # 启动定期检查任务
        self.cleanup_task = asyncio.create_task(self._periodic_cleanup())
    
    async def _periodic_cleanup(self):
        """定期检查并清理超时连接"""
        while True:
            await self.cleanup_timeout_connections()
            await asyncio.sleep(300)  # 每5分钟检查一次

    async def create_connection(self, device_info: DeviceInfo):
        async with self.lock:
            # 获取设备信息
            name = device_info.name
            ip = device_info.ip
            port = device_info.port

            if name in self.connections:
                # 检查是否是重复创建（name/ip/port都相同）
                existing_conn = self.connections[name]
                if existing_conn.info.ip == ip and existing_conn.info.port == port:
                    # 重复创建，返回成功
                    return existing_conn
                else:
                    # name已使用，但ip和port不同
                    return {'error': f'连接名称 {name} 已被使用'}

            # 创建新连接
            conn = Connection(device_info, self.logger, self.client_id)
            ret, ret_str = await conn.connect()
            if not ret:
                return {'error': ret_str}

            self.connections[name] = conn
            return conn

    async def get_connection(self, device: str) -> Connection:
        """查找或创建一个新的连接
        参数:
        - device: 设备名称
        """
        if device in self.connections:
            return self.connections[device]
        else:
            device_info = get_device_info(device)
            if device_info is None:
                return {
                    'success': False,
                    'message': "error, Not found device info or format error {}".format(device)
                }

            connection = await self.create_connection(device_info)
            
            # 检查connection_manager返回的是否是错误信息
            if isinstance(connection, dict) and 'error' in connection:
                self.logger.server_log(f"创建连接 {device} 失败, 错误信息: {connection['error']}")
                return connection
            
            return connection

    async def list_connections(self):
        """列出所有连接"""
        connections = await self.get_connections()
        # 使用get_info()方法获取可序列化的连接信息
        return [conn.get_info() for conn in connections]

    async def broadcast_command(self, cmd):
        results = {}
        async with self.lock:
            connections_copy = list(self.connections.items())

        tasks = []
        for name, conn in connections_copy:
            if conn.is_alive():
                task = asyncio.create_task(self._send_command_to_connection(name, conn, cmd))
                tasks.append(task)
            else:
                results[name] = {'error': '连接已关闭'}

        if tasks:
            task_results = await asyncio.gather(*tasks, return_exceptions=True)
            for i, (name, _) in enumerate([t for t in connections_copy if t[1].is_alive()]):
                if isinstance(task_results[i], Exception):
                    results[name] = {'error': f'发送命令失败: {str(task_results[i])}'}
                elif isinstance(task_results[i], dict) and 'error' in task_results[i]:
                    results[name] = task_results[i]
                else:
                    results[name] = {'result': task_results[i]}

        return results

    async def _send_command_to_connection(self, name, conn, cmd):
        try:
            return await conn.send_command(cmd)
        except Exception as e:
            return {'error': f'发送命令失败: {str(e)}'}

    async def close_connection(self, name):
        # 先获取锁检查连接是否存在
        async with self.lock:
            if name not in self.connections:
                return {'error': f'找不到连接: {name}'}
            conn = self.connections[name]
        
        # 释放锁后关闭连接
        if await conn.close():
            # 再次获取锁删除连接
            async with self.lock:
                # 双重检查，防止并发删除
                if name in self.connections:
                    del self.connections[name]
            return {'success': True}
        return {'success': False}

    async def close_all_connections(self):
        # 获取当前连接名称列表
        async with self.lock:
            names = list(self.connections.keys())
        
        # 并行关闭所有连接
        if not names:
            return 0
        
        tasks = []
        for name in names:
            tasks.append(self.close_connection(name))
        
        # 等待所有任务完成
        results = await asyncio.gather(*tasks)
        
        # 统计成功关闭的连接数
        count = 0
        for result in results:
            if isinstance(result, dict) and result.get('success'):
                count += 1
        return count
    
    async def cleanup_timeout_connections(self):
        """清理超时的连接
        
        检查所有连接的保活时间，如果超过阈值（默认2小时），则关闭连接
        """
        current_time = time.time()
        
        # 获取需要关闭的连接名称
        async with self.lock:
            timeout_connections = []
            for name, conn in self.connections.items():
                if current_time - conn.last_alive_time > self.AGING_THRESHOLD:
                    timeout_connections.append(name)
        
        # 关闭超时的连接
        closed_count = 0
        for name in timeout_connections:
            self.logger.log(name, f'连接因超过保活时间（{self.AGING_THRESHOLD}秒）被自动关闭')
            result = await self.close_connection(name)
            if isinstance(result, dict) and result.get('success'):
                closed_count += 1
        
        if closed_count > 0:
            self.logger.server_log(f'清理了 {closed_count} 个超时连接')